package com.cms.utils.conf;

import com.alibaba.druid.pool.DruidDataSource;
import com.cms.utils.properties.DruidProperties;
import com.cms.utils.properties.JdbcProperties;
import com.github.pagehelper.PageHelper;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.interceptor.TransactionInterceptor;

import javax.sql.DataSource;

import java.sql.SQLException;
import java.util.Properties;

/**
 * SpringBoot MyBatis数据链接配置信息<br>
 * 1.注册DataSource Druid数据源<br>
 * 2.注册数据源事务管理<br>
 * 3.注册SqlSessionFactory<br>
 */
@Configuration
@EnableTransactionManagement
@MapperScan(basePackages = "com.cms.dao")
public class MyBatisDataSourceConfig {


    private static Logger logger  = LogManager.getLogger(MyBatisDataSourceConfig.class);

    /**
     * 注册DataSource
     * @return
     */
	@Bean(destroyMethod = "close", initMethod="init")
    @Primary
    public DataSource myBatisDataSource(DruidProperties druidProperties,JdbcProperties jdbcProperties) throws SQLException {
		logger.info("------------------myBatis DruiDataSource init ---------");
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl(jdbcProperties.getUrl());
        dataSource.setUsername(jdbcProperties.getUsername());
        dataSource.setPassword(jdbcProperties.getPassword());
        dataSource.setInitialSize(jdbcProperties.getInitialSize());             //初始化链接大小
        dataSource.setMaxActive(jdbcProperties.getMaxActive());                 //连接池最大使用链接数量
        //dataSource.setMaxIdle(dbProperties.getMaxIdle());                   //连接池最大空闲,过时,暂不使用
        dataSource.setMinIdle(jdbcProperties.getMinIdle());                     //连接池最小空闲
        dataSource.setMaxWait(jdbcProperties.getMaxWait());                     //获取连接最大等待时间
        dataSource.setValidationQuery(jdbcProperties.getValidationQuery());     //验证数据库是否连通

        dataSource.setTestOnBorrow(druidProperties.isTestOnBorrow());
        dataSource.setTestOnReturn(druidProperties.isTestOnReturn());
        dataSource.setTestWhileIdle(druidProperties.isTestWhileIdle());
        //配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒
        dataSource.setTimeBetweenEvictionRunsMillis(druidProperties.getTimeBetweenEvictionRunsMillis());
        //配置一个连接在池中最小生存的时间，单位是毫秒
        dataSource.setMinEvictableIdleTimeMillis(druidProperties.getMinEvictableIdleTimeMillis());
        //打开removeAbandoned功能
        dataSource.setRemoveAbandoned(druidProperties.isRemoveAbandoned());
        // 1800秒，也就是30分
        dataSource.setRemoveAbandonedTimeout(druidProperties.getRemoveAbandonedTimeout());
        //关闭abanded连接时输出错误日志
        dataSource.setLogAbandoned(druidProperties.isLogAbandoned());
        //监控数据库
        dataSource.setFilters(druidProperties.getFilters());
        //开启池的prepared statement 池功能
        dataSource.setPoolPreparedStatements(druidProperties.isPoolPreparedStatements());
        return dataSource;
    }

    /**
     * 注册数据源事务管理
     * @return
     * @throws SQLException
     */
    @Bean(name="myBatisTransactionManager")
    public DataSourceTransactionManager myBatisTransactionManager(DataSource myBatisDataSource) throws SQLException {
        return new DataSourceTransactionManager(myBatisDataSource);
    }


    /**
     * 声明式事务
     * @param platformTransactionManager
     * @return
     */
    @Bean(name="transactionInterceptor")
    public TransactionInterceptor transactionInterceptor(PlatformTransactionManager platformTransactionManager){
        TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
        transactionInterceptor.setTransactionManager(platformTransactionManager);
        Properties transactionAttributes = new Properties();
        transactionAttributes.setProperty("create*","PROPAGATION_REQUIRED,-Throwable");
        transactionAttributes.setProperty("insert*","PROPAGATION_REQUIRED,-Throwable");
        transactionAttributes.setProperty("save*","PROPAGATION_REQUIRED,-Throwable");
        transactionAttributes.setProperty("update*","PROPAGATION_REQUIRED,-Throwable");
        transactionAttributes.setProperty("delete*","PROPAGATION_REQUIRED,-Throwable");
        transactionAttributes.setProperty("select*","PROPAGATION_REQUIRED,-Throwable,readOnly");
        transactionInterceptor.setTransactionAttributes(transactionAttributes);
        return transactionInterceptor;
    }
    
    @Bean
    public BeanNameAutoProxyCreator transactionAutoProxy(){
        BeanNameAutoProxyCreator transactionAutoProxy = new BeanNameAutoProxyCreator();
        transactionAutoProxy.setProxyTargetClass(true);
        transactionAutoProxy.setBeanNames("*Service");
        transactionAutoProxy.setInterceptorNames("transactionInterceptor");
        return transactionAutoProxy;
    }

    /**
     * 注册数据源事务管理
     * @param myBatisDataSource
     * @return
     * @throws Exception
     */
    @Bean
    public SqlSessionFactory myBatisSqlSessionFactory(DataSource ds,DruidProperties druidProperties) throws Exception {
        final SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        //添加数据源
        factory.setDataSource(ds);
        //实体类扫描路径
        factory.setTypeAliasesPackage(druidProperties.getTypeAliasesPackage());
        //Mapper文件位置
        factory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(druidProperties.getMapperLocation()));
        //mybatisConfig 文件
        factory.setConfigLocation(new DefaultResourceLoader().getResource(druidProperties.getConfigLocation()));
        //分页插件
        PageHelper pageHelper = new PageHelper();
        Properties properties = new Properties();
        properties.setProperty("offsetAsPageNum","true");
        properties.setProperty("rowBoundsWithCount","true");
        properties.setProperty("dialect","mysql");//配置mysql数据库的方言
        properties.setProperty("reasonable", "true");
        properties.setProperty("supportMethodsArguments", "true");
        properties.setProperty("returnPageInfo", "check");
        properties.setProperty("params", "count=countSql");
        pageHelper.setProperties(properties);
        factory.setPlugins(new Interceptor[]{pageHelper});
        factory.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
        return factory.getObject();
    }
}